// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Data.SqlClient;
using System.Data;
using Microsoft.TeamFoundation.Migration.Toolkit.VC;
using System.Transactions;
using System.Diagnostics;

namespace Microsoft.TeamFoundation.Migration.Toolkit
{
    /// <summary>
    /// The state of the current action.  It is possible that a single change grouping could be loaded with
    /// migration actions already in the complete or skipped state.  Only pending actions should be executed
    /// during the migration process.
    /// </summary>
    public enum ActionState
    {
        Pending = 0,
        Complete = 1,
        Skipped = 2
    }

    /// <summary>
    /// The base type for all migration actions in a ChangeGrouping.
    /// </summary>
    public abstract class MigrationAction : IMigrationAction
    {
        protected MigrationAction(ChangeGrouping parent)
            : this(parent, DefaultActionId)
        {
        }

        protected MigrationAction(ChangeGrouping parent, int actionId)
        {
            m_parent = parent;
            m_actionId = actionId;
        }

        /// <summary>
        /// Creates a new migration action instance using a default transaction.
        /// </summary>
        internal abstract void CreateNew();


        /// <summary>
        /// Creates a new migration action instannce in the context of the provided transaction.
        /// </summary>
        /// <param name="trx">The transaction in which the migration action is created.</param>
        internal abstract void CreateNew(IMigrationTransaction trx);

        /// <summary>
        /// Updates an existing migration action using a default transaction.
        /// </summary>
        internal abstract void UpdateExisting();

        /// <summary>
        /// Updates an exsiting migration action using the provided transactions.
        /// </summary>
        /// <param name="trx">The transaction in which the migration action is updated</param>
        internal abstract void UpdateExisting(IMigrationTransaction trx);

        #region IMigrationAction<int> Members

        /// <summary>
        /// The ChangeGrouping the migation action is associated with.
        /// </summary>
        public ChangeGrouping ChangeGroup
        {
            get
            {
                return m_parent;
            }
            internal set
            {
                m_parent = value;
            }
        }

        /// <summary>
        /// The source item, on the source server, of the item being migrated.  If this is an operation that is updating the target
        /// system content (e.g. add or edit) this is the item used to download the updated content.  If the operation does not
        /// require downloaded content (e.g. delete and label) this property may be null.
        /// </summary>
        public IMigrationItem SourceItem
        {
            get
            {
                return m_sourceItem;
            }
            set
            {
                m_sourceItem = value;
            }
        }

        /// <summary>
        /// The source item of the migration action on the target server.  If the operation is a branch, merge or rename operation
        /// this item will represent the source of the operation.  Otherwise this property may be null.
        /// </summary>
        public IMigrationItem TargetSourceItem
        {
            get
            {
                return m_tfsSourceItem;
            }
            set
            {
                m_tfsSourceItem = value;
            }
        }

        /// <summary>
        /// The target item of the migration action on the target server.  All operations have a target item.
        /// </summary>
        public IMigrationItem TargetTargetItem
        {
            get
            {
                return m_tfsTargetItem;
            }
            set
            {
                m_tfsTargetItem = value;
            }
        }

        /// <summary>
        /// The change action this migration item contains.
        /// </summary>
        public ChangeAction Action
        {
            get
            {
                return m_changeType;
            }
            set
            {
                m_changeType = value;
            }
        }


        /// <summary>
        /// If true the action is performed recursively, otherwise not.
        /// </summary>
        public bool Recursive
        {
            get
            {
                return m_recursive;
            }
            set
            {
                m_recursive = value;
            }
        }

        /// <summary>
        /// The order in which this action should be executed relative to other actions in the change grouping.
        /// </summary>
        public int Order
        {
            get
            {
                return m_order;
            }
            set
            {
                m_order = value;
            }
        }

        /// <summary>
        /// The current state of the action.
        /// </summary>
        public ActionState State
        {
            get
            {
                return m_state;
            }
            set
            {
                m_state = value;
                UpdateExisting();
            }
        }

        /// <summary>
        /// If the action is a Label operation this is the name of the label.
        /// </summary>
        public string Label
        {
            get
            {
                return m_label;
            }
            set
            {
                m_label = value;
            }
        }

        /// <summary>
        /// If the action is an encoding operation this is the new encoding type.
        /// </summary>
        public string Encoding
        {
            get
            {
                return m_encoding;
            }
            set
            {
                m_encoding = value;
            }
        }

        /// <summary>
        /// Type of the action item Any = 0, Folder = 1, File = 2,
        /// </summary>
        public ItemType ItemType
        {
            get
            {
                return m_itemType;
            }
            set
            {
                m_itemType = value;
            }
        }

        /// <summary>
        /// An value that uniquely identifies the action in the persistence store.  This value is used by UpdateExisting
        /// to identify the action in the data store.
        /// </summary>
        protected int ActionId
        {
            get
            {
                return m_actionId;
            }
            set
            {
                m_actionId = value;
            }
        }

        /// <summary>
        /// This Property is only used for undelete, branch and merge action. 
        /// For undelete action, this is the version in which the item was deleted.
        /// For branch action, this is the branch from version
        /// For merge action, this is the start version of merge
        /// </summary>
        public string Version
        {
            get
            {
                return m_version;
            }
            set
            {
                m_version = value;
            }
        }

        /// <summary>
        /// This Property is only used for merge action. 
        /// For merge action, this is the end version of merge
        /// </summary>
        public string MergeVersionTo
        {
            get
            {
                return m_mergeVersionTo;
            }
            set
            {
                m_mergeVersionTo = value;
            }
        }        

        #endregion

        /// <summary>
        /// Updates the state without an immediate database upate.
        /// </summary>
        /// <param name="state">The new action state.</param>
        internal void setStateWithoutUpdatingDb(ActionState state)
        {
            m_state = state;
        }

        ChangeGrouping m_parent;
        bool m_recursive;
        ChangeAction m_changeType;
        IMigrationItem m_tfsTargetItem;
        IMigrationItem m_tfsSourceItem;
        IMigrationItem m_sourceItem;
        string m_version;
        string m_mergeVersionTo;
        int m_order = -1;
        ActionState m_state = ActionState.Pending;
        int m_actionId = -1;

        string m_label;
        string m_encoding;

        ItemType m_itemType;

        // the default action ID will be set to something else when it is persisted into the data store.
        // For example in SQL this will be the row id of the action.
        const int DefaultActionId = -1;
    }
}
